package accounts

import (
	"github.com/shopspring/decimal"
	"github.com/sirupsen/logrus"
	"github.com/tietang/dbx"
)

// 账户表DAO操作结构体对象
type AccountDao struct {
	runner *dbx.TxRunner // 使用dbx.TxRunner来直接操作数据库表，包括事务操作，在外部通过初始化此成员来访问数据库账户表
}

// 查询资金/红包账户表的单实例，获取一行数据
func (dao *AccountDao) GetOne(accountNo string) *Account {
	a := &Account{AccountNo: accountNo}
	ok, err := dao.runner.GetOne(a) // 适用于通过唯一索引查询的场景，将查询结果映射到a对应的PO结构体对象里
	if err != nil {
		logrus.Error(err)
		return nil
	}
	if !ok { // 数据不存在
		return nil
	}
	return a
}

// 通过用户ID和账户类型来查询资金/红包账户表信息
func (dao *AccountDao) GetByUserId(userId string, accountType int) *Account {
	a := &Account{}
	sql := "select * from account where user_id=? and account_type=? "
	ok, err := dao.runner.Get(a, sql, userId, accountType) // 适用于不通过唯一索引查询的场景，将查询结果映射到a对应的PO结构体对象里
	if err != nil {
		logrus.Error(err)
		return nil
	}
	if !ok {
		return nil
	}
	return a
}

// 资金/红包账户数据的插入
func (dao *AccountDao) Insert(a *Account) (id int64, err error) {
	rs, err := dao.runner.Insert(a)
	if err != nil {
		return 0, err
	}
	return rs.LastInsertId() // 因只插入一条记录，所以返回已经插入的记录的ID
}

// 资金/红包账户余额的更新，入参：amount为负数表示扣减；为正数表示增加
// 乐观锁：就是在where条件后加上一个限定条件，and balance>=-1*CAST(? AS DECIMAL(30,6))就是在扣减时要判断余额必须大小扣减金额
func (dao *AccountDao) UpdateBalance(accountNo string, amount decimal.Decimal) (rows int64, err error) {
	sql := "update account " +
		" set balance=balance+CAST(? AS DECIMAL(30,6))" +
		" where account_no=? " +
		" and balance>=-1*CAST(? AS DECIMAL(30,6)) "

	rs, err := dao.runner.Exec(sql, amount.String(), accountNo, amount.String())
	if err != nil {
		return 0, err
	}
	return rs.RowsAffected() // 返回受影响的行数，如果更新成功-返回1，否则返回小于1的数
}

// 资金/红包账户状态更新
func (dao *AccountDao) UpdateStatus(accountNo string, status int) (rows int64, err error) {
	sql := "update account set status=? " + " where account_no=? "
	rs, err := dao.runner.Exec(sql, status, accountNo)
	if err != nil {
		return 0, err
	}
	return rs.RowsAffected() // 返回受影响的行数，如果更新成功-返回1，否则返回小于1的数
}
